/*
 *
 *  * Copyright (c) iwindplus Technologies Co., Ltd.2024-2030, All rights reserved.
 *
 *
 */

package com.iwindplus.base.http.client.domain.property;

import java.time.Duration;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import reactor.netty.resources.ConnectionProvider;
import reactor.netty.transport.ProxyProvider;

/**
 * WebClient配置相关属性.
 *
 * @author zengdegui
 * @since 2019/6/12
 */
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "web.client")
public class WebClientProperty {

    /**
     * 是否启用.
     */
    @Builder.Default
    private Boolean enabled = Boolean.TRUE;

    /**
     * 是否启用观察.
     */
    @Builder.Default
    private Boolean enabledObservation = Boolean.TRUE;

    /**
     * 是否开启日志详情.
     */
    @Builder.Default
    private Boolean enableLoggingRequestDetails = Boolean.TRUE;

    /**
     * 是否开启请求日志.
     */
    @Builder.Default
    private Boolean enabledRequestLog = Boolean.TRUE;

    /**
     * 是否启用Wiretap.
     */
    @Builder.Default
    private Boolean enabledWiretap = Boolean.FALSE;

    /**
     * 是否启用压缩.
     */
    @Builder.Default
    private Boolean enabledCompression = Boolean.TRUE;

    /**
     * 最大内存大小.
     */
    @Builder.Default
    private Integer maxInMemorySize = 512 * 1024;

    /**
     * 是否启用接收缓冲区和发送缓冲区的大小.
     */
    @Builder.Default
    private Boolean enabledSoSndBuf = Boolean.TRUE;

    /**
     * 接收缓冲区和发送缓冲区的大小.
     */
    @Builder.Default
    private Integer soSndBuf = 512 * 1024;

    /**
     * 连接超时时间（单位：秒）.
     */
    @Builder.Default
    private Duration connectTimeout = Duration.ofSeconds(10);

    /**
     * 响应超时时间（单位：秒）.
     */
    @Builder.Default
    private Duration responseTimeout = Duration.ofSeconds(10);

    /**
     * 读取超时时间（单位：秒）.
     */
    @Builder.Default
    private Duration readTimeout = Duration.ofSeconds(10);

    /**
     * 写入超时时间（单位：秒）.
     */
    @Builder.Default
    private Duration writeTimeout = Duration.ofSeconds(10);

    /**
     * 最大初始行长度.
     */
    @Builder.Default
    private Integer maxInitialLineLength = 8192;

    /**
     * 最大头长度.
     */
    @Builder.Default
    private Integer maxHeaderSize = 8192;

    /**
     * 缓存大小.
     */
    @Builder.Default
    private Integer maxChunkSize = 8192;

    /**
     * 线程池相关属性.
     */
    @Builder.Default
    @NestedConfigurationProperty
    private Pool pool = new Pool();

    /**
     * 代理相关属性.
     */
    @Builder.Default
    @NestedConfigurationProperty
    private Proxy proxy = new Proxy();

    /**
     * 重试相关属性.
     */
    @Builder.Default
    @NestedConfigurationProperty
    private Retry retry = new Retry();

    /**
     * 线程池相关属性.
     *
     * @author zengdegui
     * @since 2023/6/1
     */
    @Data
    @SuperBuilder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Pool {

        /**
         * 线程池类型
         */
        @Builder.Default
        private PoolType type = PoolType.ELASTIC;

        /**
         * 线程池名称.
         */
        @Builder.Default
        private String name = "webClientPool";

        /**
         * 最大连接数.
         */
        @Builder.Default
        private Integer maxConnections = ConnectionProvider.DEFAULT_POOL_MAX_CONNECTIONS;

        /**
         * 等待超时时间（单位：秒）仅适用于FIXED类型.
         */
        @Builder.Default
        private Duration pendingAcquireTimeout = Duration.ofSeconds(45);

        /**
         * 最大空闲时间（单位：秒）.
         */
        @Builder.Default
        private Duration maxIdleTime = Duration.ofSeconds(60);

        /**
         * 最大生命周期时间（单位：秒）.
         */
        @Builder.Default
        private Duration maxLifeTime = Duration.ofSeconds(60);

        /**
         * 以指定的时间间隔在后台执行定期驱逐检查。默认情况下已禁用.
         */
        @Builder.Default
        private Duration evictionInterval = Duration.ZERO;

        /**
         * 允许在Micrometer中收集和注册通道池指标。默认情况下已禁用.
         */
        @Builder.Default
        private Boolean metrics = Boolean.FALSE;

        /**
         * 线程池类型枚举.
         *
         * @author zengdegui
         * @since 2023/6/1
         */
        public enum PoolType {

            /**
             * Elastic pool type.
             */
            ELASTIC,

            /**
             * Fixed pool type.
             */
            FIXED,

            /**
             * Disabled pool type.
             */
            DISABLED

        }

    }

    /**
     * 代理相关属性.
     *
     * @author zengdegui
     * @since 2023/6/1
     */
    @Data
    @SuperBuilder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Proxy {

        /**
         * 是否开启代理.
         */
        @Builder.Default
        private Boolean enabled = Boolean.FALSE;

        /**
         * 代理类型.
         */
        @Builder.Default
        private ProxyProvider.Proxy type = ProxyProvider.Proxy.HTTP;

        /**
         * 主机.
         */
        private String host;

        /**
         * 端口.
         */
        private Integer port;

        /**
         * 用户名.
         */
        private String username;

        /**
         * 密码.
         */
        private String password;

        /**
         * 用于配置主机列表的正则表达式（Java）。应该直接访问，绕过代理.
         */
        private String nonProxyHostsPattern;

    }

    /**
     * 重试相关属性.
     *
     * @author zengdegui
     * @since 2023/6/1
     */
    @Data
    @SuperBuilder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Retry {

        /**
         * 是否启用.
         */
        @Builder.Default
        private Boolean enabled = Boolean.TRUE;

        /**
         * 最大重试次数.
         */
        @Builder.Default
        private Integer maxAttempts = 3;

        /**
         * 重试间隔（单位：秒）.
         */
        @Builder.Default
        private Duration period = Duration.ofSeconds(1);

        /**
         * 最大回退超时时间（单位：秒）.
         */
        @Builder.Default
        private Duration maxBackoffTimeout = Duration.ofSeconds(2);

    }

}
